import {xmlToJsonByAttr} from "../parser/XmlParser";
import MainModel from "../instance/MainModel";
import ModuleModel from "../instance/ModuleModel";
import jQuery from 'jquery';
import {stringUtils} from "../../utils/stringUtils";

const modelFile = new RegExp(/(http|https|file):\/\/(\/)?([^\:|\/]+)(\:\d*)?(.*\/)([^#|\?|\n]+)?(#.*)?(\?.*)?/i);

export default class ModelLoader {

    static loadModel(launcher, url) {
        const mainUrl = testFile(url);
        if (mainUrl.url === undefined) {
            throw Error('can not found main.xml');
        }
        if (mainUrl.absolute === false) {
            mainUrl.url = stringUtils.urlJoin(MidWayConfig.BasePath, url);
        }
        return jQuery.ajax({
            url: mainUrl.url,
            method: 'GET',
            dataType: "text",
            cache: false,
            async: false
        }).then(data => {
            const result = pageXMLParse(data);
            result.baseUrl = mainUrl.baseUrl;
            questionXMLPage(launcher, result);
            const model = result.getAttribute('model');
            let questionModel = {};
            if (model.length > 0) {
                const properties = model[0].getAttribute("properties");
                properties.forEach(property => {
                    if (property.type === 'json') {
                        questionModel[property.name] = JSON.parse(property.value);
                    } else if (property.type === 'jsonFile') {
                        let url = stringUtils.urlJoin(mainUrl.baseUrl, 'pages', property.value);
                        jQuery.ajax({
                            url: url,
                            dataType: "json",
                            async: false
                        }).done(data => {
                            questionModel[property.name] = data;
                        });
                    } else {
                        questionModel[property.name] = property.value;
                    }
                });
            }
            return questionModel;
        })
    }
}

function pageXMLParse(text) {
    const $dom = jQuery(jQuery.parseXML(text));
    let model = new MainModel(), commonPages = model.getAttribute('commons'),
        index = 0, parentTagName;

    $dom.find('page').each(function (i, page) {
        const pageInfo = xmlToJsonByAttr(page, ['id', 'name', 'href', 'preview']);
        pageInfo.id = pageInfo.id || 'page_' + index;
        parentTagName = page.parentNode.tagName.toLowerCase();
        if (parentTagName === 'folder') {
            if (pageInfo.name) {
                commonPages.addItem(pageInfo.name, pageInfo);
            }
        } else {
            if (parentTagName === 'coursewareobject') {
                const rootPath = page.parentNode.getAttribute("rootPath");
                pageInfo.href = rootPath + pageInfo.href;
            }
            model.addPage(pageInfo);
        }
        index++;
    });
    return model;
}

function questionXMLPage(launcher, page) {
    const pages = page.getPages();
    if (pages && pages.length > 0) {
        const questionUrl = stringUtils.urlJoin(page.baseUrl, pages[0].href);
        jQuery.ajax({
            url: questionUrl,
            method: "GET",
            async: false
        }).done(data => {
            jQuery(data).find('page').children('modules').each((index, element) => {
                questionXMLParse(launcher, page, element);
            });
        });
    }
}

function questionXMLParse(launcher, parent, modules) {
    let index = 0;
    jQuery(modules).children('module, addonModule').each((i, module) => {
        const model = new ModuleModel();
        let modelConfig = xmlToJsonByAttr(module, ['addonId', 'moduleId', 'presenterId', 'id', 'isVisible', 'isLocked', 'style', {
            'lazy-init': function (value) {
                return value.toLowerCase() === 'true';
            }
        }]);
        if (modelConfig.addonId === launcher || modelConfig.moduleId === launcher) {
            if (!modelConfig.presenterId && modelConfig.addonId) {
                modelConfig.presenterId = modelConfig.addonId;
            }
            modelConfig.id = modelConfig.id || 'module_' + index;
            $(module).children().each(function (i, element) {
                const fn = parseModule[element.tagName];
                if (jQuery.isFunction(fn)) {
                    fn(model, element);
                }
            });
            parent.addModule(model);
            index++;
        }
    });
}

function testFile(url) {
    if (url.indexOf('main.xml') === -1) {
        console.error("can not found main.xml!");
        return {absolute: false, url: undefined};
    }
    const basePath = url.replace('main.xml', '');
    const result = url.match(modelFile);
    return {absolute: result !== null, baseUrl: basePath, url: url};
}

const parseModule = {
    'style': function (module, element) {
        module.setAttribute('css', $(element).attr('href'));
        const style = $(element).text();
        if (style) {
            module.setAttribute('style', style);
        }
    },
    'events': function (module, element) {
        $(element).children('event').each(function (i, event) {
            let $event = $(event);
            let eventName = $event.attr('name');
            if (eventName) {
                let handlerList = [];
                $event.children('handler').each(function (j, handler) {
                    handlerList.push(utilsXML.toJsonByAttr(handler, [{'id': 'targetId'}, {'name': 'handlerName'}]));
                });
                if (handlerList.length) {
                    module.addEvent(eventName, handlerList);
                }
            }
        });
    },
    'properties': function (module, element) {
        buildProperty(element, function (oProp) {
            module.addProperty(oProp);
        });
    }
};

function buildProperty(element, fn) {
    jQuery(element).children('property').each(function (i, prop) {
        let oProp;
        if (prop.getAttribute('type') === 'list') {
            oProp = utilsXML.toJsonByAttr(prop, ['name', 'type']);
            oProp.value = [];
            jQuery(prop).find('items>item').each(function (i, item) {
                let itemProps = [];
                buildProperty(item, function (oProp) {
                    itemProps.push(oProp);
                });
                oProp.value.push(itemProps);
            });
        } else {
            oProp = xmlToJsonByAttr(prop, ['name', 'type', 'value']);
            let sText = jQuery.trim($(prop).text());
            if (sText) {
                oProp.text = sText;
            }
        }
        fn(oProp);
    });
}

